# v1版本
import os
import sys
import time
from ftplib import FTP
from pathlib import Path
import mne as mne
import numpy as np
from scipy.io import loadmat, savemat
import threading
import warnings
warnings.filterwarnings("ignore", category=RuntimeWarning)
from datetime import datetime

def ftpconnect(host, port, username=None, password=None):
    ftp = FTP()
    ftp.connect(host, port)
    ftp.login(username, password)
    return ftp

# 从本地上传文件到ftp


def uploadfile(ftp, localpath, remotepath):
    bufsize = 1024  # 缓冲区大小
    fp = open(localpath, 'rb')  # 二进制读取文件
    # 本地上传到ftp服务器remotepath路径下
    ftp.storbinary('STOR ' + remotepath, fp, bufsize)
    ftp.set_debuglevel(0)  # 关闭调试信息输出
    fp.close()


class BP_Recorder():
    def __init__(self, vhdr_path, save_path, interval, vmrk_max_len, chanloc_path,
                 conf_path, host, port, user, pwd, id,name, redirect_text):
        self.vhdr_path = vhdr_path
        self.vmrk_path = os.path.splitext(self.vhdr_path)[0] + ".vmrk"
        self.save_path = save_path
        self.interval = interval
        # self.start = start
        # self.end = end
        self.vmrk_max_len = vmrk_max_len
        self.vmrk_start_len = vmrk_max_len
        self.chanloc_path = chanloc_path
        self.conf_path = conf_path
        self.host = host
        self.port = port
        self.user = user
        self.pwd = pwd
        if len(id) == 0:
            self.id = "sub001"
        else:
            self.id = id
        if len(name) == 0:
            self.name = "fb"
        else:
            self.name = name
        self.should_stop = threading.Event()
        self.redirect_text = redirect_text


    def judged_input(self):

        if len(self.vhdr_path) == 0:
            print("[Warning]:数据文件错误 !")
            return False
        elif not os.path.exists(self.save_path):
            print("[Warning]:保存路径为不能为空 !")
            return False
        elif not isinstance(self.interval, (int, float)) or self.interval <= 0:
            print("[Warning]:切片长度不能小于0 !")
            return False
        elif not os.path.exists(self.chanloc_path):
            print("[Warning]:导入的导联文件不存在 !")
            return False
        elif not os.path.exists(self.conf_path) or not Path(self.conf_path).suffix == ".conf":
            print("[Warning]:参数配置文件错误 !")
            return False
        else:
            return True


    def get_vmrk(self):

        vmrk_min_len = self.vmrk_max_len  # 更新行数
        events_list = []
        with open(self.vmrk_path) as vmrkfile:
            lines = vmrkfile.readlines()  # 读取vmrk文件中的所有行
            self.vmrk_max_len = max(self.vmrk_max_len, len(lines))  # 更新最大长度
            # boundery

            event_infor = lines[self.vmrk_start_len].split(',')
            code, type, latency = event_infor[0], event_infor[1], (int)(
                event_infor[2])

            code = code.split('=')[-1]
            if type == '':
                type = 'boundary'

            events_list.append([(latency, code, type)])

            for i in range(vmrk_min_len, self.vmrk_max_len):
                if i == self.vmrk_start_len:
                    continue
                event_infor = lines[i].split(',')
                code, type, latency = event_infor[0], event_infor[1], (int)(
                    event_infor[2])
                code = code.split('=')[-1]

                if self.start_point <= latency and latency < self.end_point:
                    latency = latency - self.start_point
                    events_list.append([(latency, code, type)])
                else:
                    self.vmrk_max_len = i
                    break
        # convert to numpy array
        # 添加字段在此处添加，注意字段格式以及字段对准
        dt = np.dtype([('latency', 'f8'), ('code', 'S50'),
                      ('type', 'S20')])  # 用于定义结构化数组的数据类型
        events = np.array(events_list, dtype=dt)  # 将events_list转换为一个NumPy数组
        return events

    def load_raw(self):
        file_ext = os.path.splitext(self.vhdr_path)[1].lower()  # 扩展名
        if file_ext == ".vhdr":
            raw = mne.io.read_raw_brainvision(self.vhdr_path, verbose=False)
        elif file_ext == ".EDF":
            raw = mne.io.read_raw_edf(self.vhdr_path, verbose=False)
        return raw

    def isupdat_data(self):
        print("等待更新：", end=" ")
        wait_time = 0
        while not self.should_stop.is_set():
            temp_point = mne.io.read_raw_brainvision(
                self.vhdr_path, verbose=False).get_data().shape[1]

            if temp_point >= self.end_point:
                print()
                return True
            elif temp_point >= self.start_point and temp_point < self.end_point:

                # curent_time = round(temp_point / self.srate)
                print(".", end=" ")
                time.sleep(1)
                wait_time = wait_time + 1
                if wait_time >= self.interval:
                    print()
                    return True

                continue
            else:
                print()
                return False
        print()

    def slide_vhdr(self):
        if not self.judged_input():
            return
        start_text = "*****采集开始*****"
        current_time = datetime.now()
        formatted_time = current_time.strftime('%Y-%m-%d %H:%M:%S')
        print("[" + formatted_time + "]: " +start_text)

        # self.queue.put(start_text)
        # 读取BrainVision格式的脑电图数据文件（扩展名为.vhdr）
        raw = mne.io.read_raw_brainvision(self.vhdr_path, verbose=False)
        self.srate = raw.info['sfreq']
        chanlocs = loadmat(self.chanloc_path)['chanlocs']
        # -----------------------------------------------------------
        #实时更新数据
        # self.start_point = raw.get_data().shape[1]  # 二维即时间点数
        self.start_point = 0
        start_time = round(self.start_point / self.srate)

        while not self.should_stop.is_set():

            self.end_point = self.start_point + self.interval * self.srate
            end_time = start_time + self.interval
            # slide data
            print('\n')
            updat_text = "数据段：[ " + str(start_time) + "s — " + str(end_time) + "s ]"
            print(updat_text)
            # self.queue.put(updat_text)
            # flage = self.isupdat_data()
            time.sleep(5)
            flage = True
            if not flage:
                # end_text = "==========更新结束=========\n"
                # print(end_text)
                # current_time = datetime.now()
                # formatted_time = current_time.strftime('%Y-%m-%d %H:%M:%S')
                # print("[" + formatted_time + "]:")
                # # self.queue.put(end_text)
                break

            data = mne.io.read_raw_brainvision(
                self.vhdr_path, verbose=False).get_data()
            # print(data[:, 1:2])
            # data里面的数据是mv，改为uv
            data_slide = data[:, int(self.start_point):int(self.end_point) + 1]  # nV
            current_time = datetime.now()
            collect_time = current_time.strftime('%Y%m%d')
            filename = self.id + "_" + self.name + "_" + str(start_time) + "_" + str(end_time) + "_" + collect_time
            event = self.get_vmrk()
            save_path_temp = os.path.join(self.save_path, filename + ".mat")
            savemat(
                save_path_temp,
                {
                    'EEG': {
                        'filename': filename,
                        'data': data_slide,
                        'srate': self.srate,
                        'chanlocs': chanlocs,
                        'event': event
                    }
                }
            )
            slide_text = "slide successfull !"
            print(slide_text)
            # self.queue.put(slide_text)

            # --------
            try:
                ftp = ftpconnect(self.host, self.port, self.user, self.pwd)

                uploadfile(ftp, save_path_temp,
                           save_path_temp.split(os.sep)[-1])

                uploadfile(ftp, self.conf_path,
                           self.conf_path.split(os.sep)[-1])

                print("upload successfull !")
            except Exception as e:
                # upload_text = "Error to connect to peer!\n"
                print("Error to connect to peer !")
                print(e)

            self.start_point = self.end_point
            # self.end_point = self.start_point + self.interval * self.srate
            start_time = end_time

        end_text = "*****采集结束*****"
        print('\n')
        current_time = datetime.now()
        formatted_time = current_time.strftime('%Y-%m-%d %H:%M:%S')
        print("[" + formatted_time + "]: " + end_text)

def main():

    # bp_record.get_vmrk()

    try:

        vhdr_path = "/home/webrain/Desktop/learn/project/feedback/mycode/feedback_py/test_data/fb_01.vhdr"
        save_path = "/home/webrain/Desktop/learn/project/feedback/mycode/feedback_py/slide_data"
        interval = 5

        vmrk_max_len = 11
        chanloc_path = "/home/webrain/Desktop/learn/project/feedback/mycode/feedback_py/lib/chanlocs_v3.mat"
        conf_path = "/home/webrain/Desktop/learn/project/feedback/mycode/feedback_py/lib/fb_params.conf"
        # ready to slide
        # time.sleep(interval)
        host = "192.168.0.10"
        port = 2121
        user = "demo"
        pwd = "demo"
        remote_path = "/home/zorn/project/feedback/slide_data"
        # vhdr_path, save_path, inr, st, end, vmrk_max_len, chanloc_path, conf_path, host, port, user="demo", pwd="demo"):
        bp_record = BP_Recorder(vhdr_path, save_path, interval, vmrk_max_len, chanloc_path, conf_path,
                                host, port, user, pwd)
        bp_record.slide_vhdr()
        # pass
    except KeyboardInterrupt:
        print("==========slide结束==========")


if __name__ == "__main__":
    main()
